/*
 * (C) Copyright 2013
 * David Feng <fenghua@phytium.com.cn>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <div64.h>
#include <linux/compiler.h>

/*
 * Genertic Timer implementation of __udelay/get_timer/get_ticks/get_tbclk
 * functions. If any other timers used, another implementation should be
 * placed in platform code.
 */

static inline u64 get_cntfrq(void)
{
	u64 cntfrq;
	asm volatile("mrs %0, cntfrq_el0" : "=r" (cntfrq));
	return cntfrq;
}

static inline u64 tick_to_time(u64 tick)
{
	tick *= CONFIG_SYS_HZ;
	do_div(tick, get_cntfrq());
	return tick;
}

static inline u64 time_to_tick(u64 time)
{
	time *= get_cntfrq();
	do_div(time, CONFIG_SYS_HZ);
	return time;
}

/*
 * Generic timer implementation of get_tbclk()
 */
ulong __weak get_tbclk(void)
{
	return CONFIG_SYS_HZ;
}

/*
 * Generic timer implementation of get_timer()
 */
ulong __weak get_timer(ulong base)
{
	u64 cval;

	isb();
	asm volatile("mrs %0, cntpct_el0" : "=r" (cval));

	return tick_to_time(cval) - base;
}

/*
 * Generic timer implementation of get_ticks()
 */
unsigned long long __weak get_ticks(void)
{
	return get_timer(0);
}

/*
 * Generic timer implementation of __udelay()
 */
void __weak __udelay(ulong usec)
{
	unsigned long ticks, limit;

	limit = get_ticks() + usec/1000;

	do {
		ticks = get_ticks();
	} while (ticks < limit);
}
